package com.unibuy.smartdevice.tools;

import android.content.Context;
import android.util.Log;

import com.unibuy.smartdevice.exception.ErrorCode;
import com.unibuy.smartdevice.exception.Logs;
import com.unibuy.smartdevice.exception.LogsEmptyException;
import com.unibuy.smartdevice.exception.LogsFileNullException;
import com.unibuy.smartdevice.exception.LogsIOException;
import com.unibuy.smartdevice.exception.LogsMalformedURLException;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;

public class HttpConnect {
    public enum ContentType {
        X_WWW_FORM_URLENCODEED("application/x-www-form-urlencoded"),
        JSON("application/json"),
        ;

        private String typeString;

        ContentType(String s) {
            this.typeString = s;
        }

        public String getTypeString() {
            return typeString;
        }
    }

    private Logs logs;
    private String PARTNER_KEY = "partner_v1T5HZGz65di4GAMVAtvN6rCPzlpdDKNv3It1BNog0WTxPUgKG1S3KSq";
    private int responseCode;
    private String recevieData;

    public String getRecevieData() {
        return this.recevieData;
    }

    public HttpConnect() {
        this.logs = new Logs(this.getClass());
    }

    public int formPost(String urlString, String data, String cookie, String referer, ContentType contentType, Map<String, String> mapByRequestProperty) throws LogsMalformedURLException, LogsIOException {
        logs.debug("[form post]" + "url:" + urlString + " data:" + data);

        String charset = "UTF-8";
        try {
            URL url = new URL(urlString);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setUseCaches(false);
            httpURLConnection.setAllowUserInteraction(true);
            httpURLConnection.setInstanceFollowRedirects(true);
            HttpURLConnection.setFollowRedirects(true);

            if (cookie != null) {
                httpURLConnection.setRequestProperty("Cookie", cookie);
            }
            if (referer != null) {
                httpURLConnection.setRequestProperty("Referer", referer);
            }
            httpURLConnection.setRequestProperty("Content-Type", contentType.getTypeString());
            httpURLConnection.setRequestProperty("Content-Length", Integer.toString(data.toString().getBytes().length));
            if (mapByRequestProperty != null) {
                for (String key: mapByRequestProperty.keySet()) {
                    httpURLConnection.setRequestProperty(key, mapByRequestProperty.get(key));
                    logs.debug(key + ":" + mapByRequestProperty.get(key));
                }
            }
            DataOutputStream dataOutputStream = new DataOutputStream(httpURLConnection.getOutputStream());
            dataOutputStream.write(data.toString().getBytes(charset));
            dataOutputStream.close();

            this.responseCode = httpURLConnection.getResponseCode();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), charset));
            String recevie = "";
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                recevie = recevie + line;
            }
            this.recevieData = recevie;
            bufferedReader.close();

            httpURLConnection.disconnect();

            return this.responseCode;
        } catch (MalformedURLException e) {
            throw new LogsMalformedURLException(logs, ErrorCode.INVALID_URL_FORMAT, e);
        } catch (IOException e) {
            throw new LogsIOException(logs, ErrorCode.NETWORK_CONNECTION_ERROR, e);
        }
    }

    public int formPut(String urlString, String data, String cookie, String referer, ContentType contentType, Map<String, String> mapByRequestProperty) throws LogsIOException, LogsMalformedURLException {
        logs.debug("[form put]" + "url:" + urlString + " data:" + data);

        String charset = "UTF-8";
        try {
            URL url = new URL(urlString);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setRequestMethod("PUT");
            httpURLConnection.setUseCaches(false);
            httpURLConnection.setAllowUserInteraction(true);
            httpURLConnection.setInstanceFollowRedirects(true);
            HttpURLConnection.setFollowRedirects(true);
            if (cookie != null) {
                httpURLConnection.setRequestProperty("Cookie", cookie);
            }
            if (referer != null) {
                httpURLConnection.setRequestProperty("Referer", referer);
            }
            httpURLConnection.setRequestProperty("Content-Type", contentType.getTypeString());
            httpURLConnection.setRequestProperty("Content-Length", Integer.toString(data.toString().getBytes().length));
            if (mapByRequestProperty != null) {
                for (String key: mapByRequestProperty.keySet()) {
                    httpURLConnection.setRequestProperty(key, mapByRequestProperty.get(key));
                    logs.debug(key + ":" + mapByRequestProperty.get(key));
                }
            }
            DataOutputStream dataOutputStream = new DataOutputStream(httpURLConnection.getOutputStream());
            dataOutputStream.write(data.toString().getBytes(charset));
            dataOutputStream.close();

            this.responseCode = httpURLConnection.getResponseCode();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), charset));
            String recevie = "";
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                recevie = recevie + line;
            }
            this.recevieData = recevie;
            bufferedReader.close();

            httpURLConnection.disconnect();

            return this.responseCode;
        } catch (MalformedURLException e) {
            throw new LogsMalformedURLException(logs, ErrorCode.INVALID_URL_FORMAT, e);
        } catch (IOException e) {
            throw new LogsIOException(logs, ErrorCode.NETWORK_CONNECTION_ERROR, e);
        }
    }

    public int apiPost(String urlString, String data, Map<String, String> mapByRequestProperty) throws LogsMalformedURLException, LogsIOException {
        logs.debug("[api post]" + "url:" + urlString + " data:" + data);

        String charset = "UTF-8";
        try {
            URL url = new URL(urlString);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
//            httpURLConnection.setConnectTimeout(20);
//            httpURLConnection.setReadTimeout(20);
            httpURLConnection.setDoInput(true);
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setRequestProperty("Content-Type", "application/json");
            httpURLConnection.setRequestProperty("Content-Language", Locale.getDefault().getLanguage());
            if (mapByRequestProperty != null) {
                for (String key: mapByRequestProperty.keySet()) {
                    httpURLConnection.setRequestProperty(key, mapByRequestProperty.get(key));
                    logs.debug(key + ":" + mapByRequestProperty.get(key));
                }
            }
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream());
            outputStreamWriter.write(data.toString());
            outputStreamWriter.close();

            this.responseCode = httpURLConnection.getResponseCode();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), charset));
            String recevie = "";
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                recevie = recevie + line;
            }
            this.recevieData = recevie;
            bufferedReader.close();

            httpURLConnection.disconnect();

            return this.responseCode;
        } catch (MalformedURLException e) {
            throw new LogsMalformedURLException(logs, ErrorCode.INVALID_URL_FORMAT, e);
        } catch (IOException e) {
            throw new LogsIOException(logs, ErrorCode.NETWORK_CONNECTION_ERROR, e);
        }
    }

    public int apiPut(String urlString, String data) throws LogsMalformedURLException, LogsIOException {
        logs.debug("[api Put]" + "url:" + urlString + " data:" + data.toString());

        String charset = "UTF-8";
        try {
            URL url = new URL(urlString);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setConnectTimeout(20);
            httpURLConnection.setReadTimeout(20);
            httpURLConnection.setDoInput(true);
            httpURLConnection.setRequestMethod("PUT");
            httpURLConnection.setRequestProperty("Content-Type", "application/json");
            httpURLConnection.setRequestProperty("Content-Language", Locale.getDefault().getLanguage());
            httpURLConnection.setRequestProperty("x-api-key", PARTNER_KEY);

            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream());
            outputStreamWriter.write(data.toString());
            outputStreamWriter.close();

            this.responseCode = httpURLConnection.getResponseCode();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), charset));
            String recevie = "";
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                recevie = recevie + line;
            }
            this.recevieData = recevie;
            bufferedReader.close();

            httpURLConnection.disconnect();

            return this.responseCode;
        } catch (MalformedURLException e) {
            throw new LogsMalformedURLException(logs, ErrorCode.INVALID_URL_FORMAT, e);
        } catch (IOException e) {
            throw new LogsIOException(logs, ErrorCode.NETWORK_CONNECTION_ERROR, e);
        }
    }

    public File download(String urlString, boolean force) throws LogsMalformedURLException, LogsIOException, LogsFileNullException, LogsEmptyException {
        File outputFile = getFileFromUrl(urlString);

        if (!outputFile.exists() || force) {
            if (outputFile.exists()) {
                outputFile.delete();
            }

            HttpURLConnection connection = null;
            InputStream inputStream = null;
            OutputStream outputStream = null;

            try {
                URL url = new URL(urlString + "?time=" + System.currentTimeMillis());
                connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                inputStream = connection.getInputStream();
                outputStream = new FileOutputStream(outputFile);
                // 使用 buffer 讀取並寫入
                byte[] buffer = new byte[2048];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                outputStream.flush();

                inputStream.close();
                outputStream.close();
                connection.disconnect();

                this.logs.info("download:" + outputFile.getAbsolutePath() + " url:" + urlString);
            } catch (MalformedURLException e) {
                throw new LogsMalformedURLException(logs, ErrorCode.INVALID_URL_FORMAT, e);
            } catch (IOException e) {
                throw new LogsIOException(logs, ErrorCode.NETWORK_CONNECTION_ERROR, e);
            }
        }

        return outputFile;
    }

    public void uploadFile(String uploadUrl, File logFile) {
        HttpURLConnection connection = null;
        DataOutputStream outputStream = null;
        FileInputStream fileInputStream = null;

        String boundary = "*****"; // 分隔符
        String lineEnd = "\r\n";
        String twoHyphens = "--";

        try {
            if (!logFile.exists()) {
                logs.debug("檔案不存在：" + logFile.getAbsolutePath());
                return;
            }

            logs.debug("開始上傳：" + logFile.getAbsolutePath());

            URL url = new URL(uploadUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

            outputStream = new DataOutputStream(connection.getOutputStream());

            // Multipart 表頭
            outputStream.writeBytes(twoHyphens + boundary + lineEnd);
            outputStream.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + logFile.getName() + "\"" + lineEnd);
            outputStream.writeBytes("Content-Type: text/plain" + lineEnd);
            outputStream.writeBytes(lineEnd);

            // 寫入檔案內容
            fileInputStream = new FileInputStream(logFile);
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            // 結尾
            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
            outputStream.flush();

            // 伺服器回應
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                logs.info("Log 上傳成功！");
                logFile.delete();
            } else {
                logs.debug("Log 上傳失敗，HTTP 狀態碼：" + responseCode);

                InputStream errorStream = connection.getErrorStream();
                if (errorStream != null) {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
                    StringBuilder errorResponse = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        errorResponse.append(line).append("\n");
                    }
                    logs.debug("伺服器錯誤內容：\n" + errorResponse);
                    reader.close();
                }
            }

        } catch (Exception e) {
            logs.warning(e);
        } finally {
            try {
                if (fileInputStream != null) fileInputStream.close();
            } catch (IOException ignored) {}

            try {
                if (outputStream != null) outputStream.close();
            } catch (IOException ignored) {}

            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    public File getFileFromUrl(String urlString) throws LogsFileNullException, LogsEmptyException {
        String fileName = getFileNameFromUrl(urlString);
        if (fileName.isEmpty()) {
            throw new LogsFileNullException(logs, "File null:" + fileName);
        }

        return new File(Tools.getExternalFilesDir(), fileName);
    }

    public String getFileNameFromUrl(String urlString) throws LogsEmptyException {
        if (urlString.isEmpty()) {
            throw new LogsEmptyException(logs, "Url is empty:" + urlString);
        }

        try {
            URI uri = new URI(urlString);
            String path = uri.getPath().split("\\?")[0];
            return path.substring(path.lastIndexOf('/') + 1); // 提取最後一段
        } catch (Exception e) {
            e.printStackTrace();
            return null; // 無效 URL
        }
    }
}
